package com.qyer.search.listener;

import static com.qyer.search.Constants.SENDER_COUNT;

import com.qyer.commons.exception.DBException;
import com.qyer.commons.exception.InvocationException;
import com.qyer.commons.mc.MutableCache;
import com.qyer.search.cache.mutable.MutableCaches;
import com.qyer.search.db.DMDBResourceManager;
import com.qyer.search.db.MainRedisOperator;
import com.qyer.search.db.POIInfoRedisOperator;
import com.qyer.search.db.SearchResultRedisOperator;
import com.qyer.search.engine.ForkJoinESEngine;
import com.qyer.search.report.Reporter;
import com.qyer.search.report.ReporterQueue;
import com.qyer.search.report.SearchReportItem;
import com.qyer.search.threading.DeserializerThreadPoolHolder;
import com.qyer.search.threading.SearchingThreadPoolHolder;
import com.qyer.search.threading.SortingThreadPoolHolder;
import com.qyer.search.utils.WordETLClient;
import com.qyer.words.model.Word;
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Set;

/**
 * User: Z J Wu Date: 2015/12/30 Time: 11:00 Package: com.qyer.search.listener
 */
public class ContextListener implements ServletContextListener {

  private static final Logger LOGGER = LoggerFactory.getLogger(ContextListener.class);

  @Override public void contextInitialized(ServletContextEvent sce) {
    // 初始化DB连接池
    LOGGER.info("Building dm DB connection pool.");
    try {
      LOGGER
        .info("DM connection pool is standby({}).", DMDBResourceManager.getInstance().heartbeat());
    } catch (DBException e) {
      e.printStackTrace();
      throw new RuntimeException("Container startup with error", e);
    }

    // 初始化Redis
    try {
      MainRedisOperator.getInstance().ping();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException("Main redis is not ready", e);
    }
    try {
      SearchResultRedisOperator.getInstance().ping();
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException("Search redis is not ready", e);
    }
    //////////////++++++++++++++
    /*try {
      POIInfoRedisOperator.getInstance().ping();
    } catch (Exception e) {
      throw new RuntimeException("Poiinfo redis is not ready", e);
    }*/
    //////////////+++++++++++++++

    CompositeConfiguration c = new CompositeConfiguration();
    try {
      c.addConfiguration(new PropertiesConfiguration("words_config.properties"));
    } catch (ConfigurationException e) {
      e.printStackTrace();
    }
    String wordForTest = c.getString("wordetl.testString");

    // 初始化基础词查询线程池, 测试联通.
    LOGGER.info("Testing translator. Words=[{}]", wordForTest);
    WordETLClient client = WordETLClient.getInstance();
    Set<List<Word>> possibleWordsTupleSet;
    try {
      possibleWordsTupleSet = client.getBasicWord(wordForTest);
    } catch (InvocationException e) {
      throw new RuntimeException(e);
    }

    for (List<Word> possibleWordsTuple : possibleWordsTupleSet) {
      LOGGER.info("Possible word tuple - {}", possibleWordsTuple);
    }
    // 初始化搜索集群, 获取集群健康状态
    LOGGER.info("Init current ES operator.");
    ForkJoinESEngine.getInstance().status();
    // 初始化内容汇报线程
    LOGGER.info("Init reporters.");
    for (int i = 0; i < SENDER_COUNT; i++) {
      new Thread(new Reporter(), "Reporter." + i).start();
    }
    LOGGER.info("{} reporters have created.", SENDER_COUNT);

    // 定时更新Cache
    Thread thread;
    for (MutableCache mc : MutableCaches.getInstance().MC_LIST) {
      thread = new Thread(mc, "Reloader(" + mc.getName() + ")");
      thread.start();
      LOGGER.info("MutableCache[{}] begin reloading.", mc.getDesc());
    }
    //反序列化线程池
    try {
      DeserializerThreadPoolHolder.getInstance().getService();
      LOGGER.info("反序列化线程池初始化成功！");
    }catch (Exception e){
      LOGGER.error("反序列化线程失败", e);
      this.contextDestroyed(null);
    }
    //
    try{
      SearchingThreadPoolHolder.getInstance();
      LOGGER.info("搜索线程池初始化成功！");
    }catch (Exception e){
      LOGGER.error("搜索线程池失败",e);
      this.contextDestroyed(null);
    }
    /*
    try{
      SortingThreadPoolHolder.getInstance();
      LOGGER.info("排序线程池初始化成功！");
    }catch (Exception e){
      LOGGER.error("排序线程池失败",e);
      this.contextDestroyed(null);
    }*/
    printASCII("./hello");
  }

  @Override public void contextDestroyed(ServletContextEvent sce) {
    printASCII("./bye");
    LOGGER.info("Destroy DM db resource manager.");
    DMDBResourceManager.getInstance().destroy();
    ForkJoinESEngine.getInstance().shutdown();
    try {
      SearchingThreadPoolHolder.getInstance().destroy();
    } catch (InterruptedException e) {
      LOGGER.error("Interrupt destroy thread pool.", e);
    }
    //    try {
    //      BasicWordMappingThreadPoolHolder.getInstance().destroy();
    //    } catch (InterruptedException e) {
    //      LOGGER.error("Interrupt destroy thread pool.", e);
    //    }

    //System.out.println("TYPEMAP");
    //System.out.println(MutableCaches.getInstance().PRODUCT_TYPE_MAP.getCacheContent());

    for (MutableCache mc : MutableCaches.getInstance().MC_LIST) {
      mc.stopNow();
    }

    MainRedisOperator.getInstance().destory();
    LOGGER.info("Main redis destroyed.");
    SearchResultRedisOperator.getInstance().destory();
    LOGGER.info("Search result redis destroyed.");
    /*POIInfoRedisOperator.getInstance().destory();
    LOGGER.info("poiinfo redis destroyed.");*/
    for (int i = 0; i < SENDER_COUNT; i++) {
      try {
        ReporterQueue.getInstance().putToQueue(SearchReportItem.createPill());
      } catch (InterruptedException e) {
        LOGGER.error("Put pill failed.", e);
      }
    }

    LOGGER.info("反序列化线程池终止开始");
    try {
      DeserializerThreadPoolHolder.getInstance().destroy();
      LOGGER.info("反序列化线程池终止成功");
    }catch (Exception e){
      LOGGER.error("反序列化线程池终止失败",e);
    }

    /*LOGGER.info("排序线程池终止开始");
    try {
      SortingThreadPoolHolder.getInstance().destroy();
      LOGGER.info("排序线程池终止成功");
    }catch (Exception e){
      LOGGER.error("排序线程池终止失败",e);
    }*/
  }

  private void printASCII(String file) {
    try (InputStream is = this.getClass().getClassLoader().getResourceAsStream(file);
         BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
      String line;
      while ((line = br.readLine()) != null) {
        System.out.println(line);
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}
